﻿using Furion;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.FriendlyException;
using Furion.TaskScheduler;
using FurStudy.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FurStudy.WorkerService
{
    /// <summary>
    /// 缓隔方式使用 - ISpareTimeWorker方式(在Startup.cs中注册services.AddTaskScheduler())
    /// 注：ISpareTimeWorker接口主要是用来查找定时器对象的，也就是它的实现类并未提供依赖注入功能，所以在实现类并不支持构造函数注入依赖项。
    /// </summary>
    public class JobWorker : ISpareTimeWorker
    {
        /// <summary>
        /// 3秒后执行
        /// </summary>
        /// <param name="timer"></param>
        /// <param name="account"></param>
        [SpareTime(3000,"jobName",DoOnce = true, StartNow = true)]
        public void DoSomething(SpareTimer timer, long account)
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
        }

        /// <summary>
        /// 3秒后执行(支持异步)
        /// </summary>
        /// <param name="timer"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        [SpareTime(3000, "jobName", DoOnce = true, StartNow = true)]
        public async Task DoSomethingAsync(SpareTimer timer, long account)
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            await Task.CompletedTask;
        }

        /// <summary>
        /// 每隔3秒执行
        /// </summary>
        /// <param name="timer"></param>
        /// <param name="count"></param>
        [SpareTime(3000, "jobName", StartNow = true)]
        public void DoSomethingSecondInterval(SpareTimer timer, long count)
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine($"一共执行了：{count} 次");
        }

        /// <summary>
        /// 每分钟执行
        /// </summary>
        /// <param name="timer"></param>
        /// <param name="count"></param>
        [SpareTime("* * * * *", "jobName", StartNow = true)]
        public void DoSomethingMinuteInterval(SpareTimer timer, long count)
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine($"一共执行了：{count} 次");
        }

        /// <summary>
        /// 每分钟执行(支持异步)
        /// </summary>
        /// <param name="timer"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        [SpareTime("* * * * *", "jobName", StartNow = true)]
        public async Task DoSomethingMinuteIntervalAsync(SpareTimer timer, long count)
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine($"一共执行了：{count} 次");
            await Task.CompletedTask;
        }

        #region ISpareTimeWorker说明

        // 每隔一秒执行，且立即启动
        [SpareTime(1000, "jobName1", StartNow = true)]
        public void DoSomething1(SpareTimer timer, long count)
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine($"一共执行了：{count} 次");
        }

        // 每分钟执行，且立即启动
        [SpareTime("* * * * *", "jobName2", StartNow = true)]
        public void DoSomething2(SpareTimer timer, long count)
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine($"一共执行了：{count} 次");
        }

        // 每秒执行，且等待启动
        [SpareTime("* * * * * *", "jobName3", CronFormat = CronFormat.IncludeSeconds, StartNow = false)]
        public void DoSomething3(SpareTimer timer, long count)
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine($"一共执行了：{count} 次");
        }

        // 每秒执行一次，每分钟也执行一次
        [SpareTime(1000, "jobName4", StartNow = true)]
        [SpareTime("* * * * *", "jobName5", StartNow = true)]
        public void DoSomething4(SpareTimer timer, long count)
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine($"一共执行了：{count} 次");
        }

        // 只执行一次
        [SpareTime(1000, "jobName5", StartNow = true, DoOnce = true)]
        public void DoSomething5(SpareTimer timer, long count)
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine($"一共执行了：{count} 次");
        }

        // 读取配置文件，通过 #(配置路径)
        [SpareTime("#(MyJob:Time)", "jobName6", StartNow = true, DoOnce = true)]
        public void DoSomething6(SpareTimer timer, long count)
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine($"一共执行了：{count} 次");
        }

        #endregion

        #region SpareTime静态类

        public void TestSpareTime()
        {
            double interval = 0;
            double expression = 0;

            #region 初始化任务

            // 开启间隔任务
            SpareTime.Do(interval, null);

            // 开启 Cron 表达式任务
            SpareTime.Do(expression, null);

            // 只执行一次任务
            SpareTime.DoOnce(interval, null);

            // 实现自定义任务
            SpareTime.Do(() =>
            {
                return DateTime.Now.AddMinutes(10);
            }, null);

            #endregion

            // 实现后台执行
            SpareTime.DoIt(() => { });

            // 开始一个任务
            SpareTime.Start("任务标识");

            // 暂停一个任务
            SpareTime.Stop("任务标识");
            // 还可以标记一个任务执行失败
            SpareTime.Stop("任务标识", true);

            // 取消一个任务
            SpareTime.Cancel("任务名称");

            // 销毁所有任务
            SpareTime.Dispose();

            // 获取所有任务
            var workers = SpareTime.GetWorkers();

            // 获取单个任务
            var worker = SpareTime.GetWorker("workerName");

            // 解析Cron表达式
            var nextTime = SpareTime.GetCronNextOccurrence("* * * * *");
        }

        #endregion

        #region 并行和串行执行方式

        public void TestParallelAndSerial()
        {
            // SpareTime静态方式指定
            SpareTime.Do(1000, (t, i) =>
            {
                Thread.Sleep(5000); // 模拟执行耗时任务
                Console.WriteLine($"{t.WorkerName} -{t.Description} - {DateTime.Now:yyyy-MM-dd HH:mm:ss} - {i}");
            }, "serialName", "模拟串行任务", executeType: SpareTimeExecuteTypes.Serial); // 串行执行

        }

        /// <summary>
        /// ISpareTimeWorker方式
        /// </summary>
        /// <param name="timer"></param>
        /// <param name="count"></param>
        [SpareTime(1000, "jobName1", StartNow = true, ExecuteType = SpareTimeExecuteTypes.Serial)] // 串行执行
        public void DoSomethingISpareTimeWorker(SpareTimer timer, long count)
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine($"一共执行了：{count} 次");
        }


        #endregion

        #region 任务异常处理

        /// <summary>
        /// 如果一个任务错误次数达10次 则任务将自动停止，并标记任务状态为Failed
        /// </summary>
        public void TaskExceptionDeal()
        {
            SpareTime.Do(1000, (t, c) =>
            {
                // 判断是否有异常
                if (t.Exception.Any())
                {
                    Console.WriteLine(t.Exception.Values.LastOrDefault()?.Message);
                }
                // 执行第三次抛异常
                if (c > 2)
                {
                    throw Oops.Oh("抛异常" + c);
                }
                else
                {
                    Console.WriteLine($"{t.WorkerName} -{t.Description} - {DateTime.Now:yyyy-MM-dd HH:mm:ss} - {c}");
                }
            }, "exceptionJob");
        }

        #endregion

        #region 任务中解析对象

        // 如果作用域中对数据库有任何变更操作，需手动调用SaveChanges或带Now结尾的方法。也可以使用Scoped.CreateUow(handler) 代替

        public void AnalysisObjectInTask()
        {
            // 1、SpareTime静态类中
            SpareTime.Do(1000, (timer, count) =>
            {
                Scoped.Create((_, scope) =>
                {
                    var services = scope.ServiceProvider;

                    // 获取数据库上下文
                    var dbContext = Db.GetDbContext(services);

                    // 获取仓储
                    var respository = Db.GetRepository<Person>(services);

                    // 解析其他服务
                    var otherService = services.GetService<Person>();
                    var otherService2 = App.GetService<Person>(services);
                });
            }, "任务标识");
        }

        /// <summary>
        /// ISpareTimeWorker 方式
        /// </summary>
        /// <param name="timer"></param>
        /// <param name="count"></param>
        [SpareTime(1000, "jobName1", StartNow = true, ExecuteType = SpareTimeExecuteTypes.Serial)]
        public void DoSomethingISpareTimeWorkerTask(SpareTimer timer, long count)
        {
            Scoped.Create((_, scope) =>
            {
                var services = scope.ServiceProvider;

                // 获取数据库上下文
                var dbContext = Db.GetDbContext(services);

                // 获取仓储
                var respository = Db.GetRepository<Person>(services);

                // 解析其他服务
                var otherService = services.GetService<Person>();
                var otherService2 = App.GetService<Person>(services);
            });
        }

        #endregion
    }
}
